﻿using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.Model.Core;
using DevExpress.ExpressApp.Model.NodeGenerators;

namespace EasyXaf.CloneModelView;

public class CloneModelViewNodesGeneratorUpdater : ModelNodesGeneratorUpdater<ModelViewsNodesGenerator>
{
    private IModelObjectView NewModelView(IModelViews modelViews, CloneModelViewAttribute cloneViewAttribute, IModelClass modelClass)
    {
        if (cloneViewAttribute.ViewType == CloneViewType.ListView)
        {
            var listViewModel = modelViews.AddNode<IModelListView>(cloneViewAttribute.ViewId);
            listViewModel.ModelClass = modelClass;
            return listViewModel;
        }

        if (cloneViewAttribute.ViewType == CloneViewType.LookupListView)
        {
            var listViewModel = modelViews.AddNode<IModelListView>(cloneViewAttribute.ViewId);
            listViewModel.ModelClass = modelClass;
            listViewModel.SetValue("IsLookupView", true);
            if (!modelClass.TypeInfo.IsPersistent)
            {
                listViewModel.DataAccessMode = CollectionSourceDataAccessMode.Client;
            }
            listViewModel.IsGroupPanelVisible = false;
            listViewModel.AutoExpandAllGroups = false;
            listViewModel.IsFooterVisible = false;
            return listViewModel;
        }

        if (cloneViewAttribute.ViewType == CloneViewType.DetailView)
        {
            var detailViewModel = modelViews.AddNode<IModelDetailView>(cloneViewAttribute.ViewId);
            detailViewModel.ModelClass = modelClass;
            return detailViewModel;
        }

        throw new NotImplementedException();
    }

    private void AssignAsDefaultView(CloneModelViewAttribute cloneModelViewAttribute, IModelObjectView modelView)
    {
        if (cloneModelViewAttribute.IsDefault)
        {
            if (modelView is IModelListView view)
            {
                if (cloneModelViewAttribute.ViewType != CloneViewType.LookupListView)
                {
                    view.ModelClass.DefaultListView = view;
                }
                else
                {
                    view.ModelClass.DefaultLookupListView = view;
                }
            }
            else
            {
                modelView.ModelClass.DefaultDetailView = (IModelDetailView)modelView;
            }
        }
    }

    private void GenerateModel(IModelViews views, IModelClass modelClass)
    {
        var cloneViewAttributes = modelClass.TypeInfo
            .FindAttributes<CloneModelViewAttribute>(false)
            .Where(attribute => views[attribute.ViewId] == null)
            .OrderBy(viewAttribute => viewAttribute.ViewType);
        foreach (var cloneViewAttribute in cloneViewAttributes)
        {
            var modelView = NewModelView(views, cloneViewAttribute, modelClass);
            AssignAsDefaultView(cloneViewAttribute, modelView);
            if (modelView is IModelListView listView && !string.IsNullOrEmpty(cloneViewAttribute.DetailView))
            {
                var modelDetailView = listView.Application.Views.OfType<IModelDetailView>()
                    .FirstOrDefault(view => view.Id == cloneViewAttribute.DetailView) ?? throw new NullReferenceException(cloneViewAttribute.DetailView);
                listView.DetailView = modelDetailView;
            }
        }
    }

    public override void UpdateNode(ModelNode node)
    {
        var modelClasses = node.Application.BOModel
            .Where(m => m.TypeInfo.FindAttributes<CloneModelViewAttribute>().Any());
        foreach (var modelClass in modelClasses)
        {
            GenerateModel(node.Application.Views, modelClass);
        }
    }
}
